﻿package {
	
	import flash.display.*;
	import flash.events.*;
	import flash.geom.Matrix;
	import flash.geom.Point;
	import flash.text.*; 
	
	/* This class is used to represent a point that is placed on the drawing panel */
	public class DrawPoint extends MovieClip {
		public static const POINT_SIZE:Number = 10;
		public static const ENHANCED_SIZE:Number = 16;
		public static const PIN_SIZE:Number = 6;
		public static const POINT_COLOR:uint = 0xAA8844;
		public static const PIN_COLOR:uint = 0xFFFFFF;
		public static const PIN_FIXED_COLOR:uint = 0xFFFFFF;
		public static const HIGHLIGHT_COLOR:uint = 0xFFFF00;
		public static const FIXED_COLOR:uint = 0x774400;
		public static const PINNED_FIXED_COLOR:uint = 0x444444;
		public static function toGeomPoints(arr:Array):Array
		{		
			var _gpoints:Array = new Array();		
			for each (var d:DisplayObject in arr){_gpoints.push(new Point(d.x, d.y));}
			return _gpoints;
		}
		public var id:String;
		public var _pinned:Boolean=false; // is this point pinned to current space
		public var _fixed:Boolean=false; // is this point undetable;
		public var _ppinned:Boolean=false; // is this point permanently pinned (by being both fixed and pinned at the start;
		public var pointsize:int, enhancedsize:int, pinnedsize:int;
		//public objects
		public var drawSegments:Array, drawAngles:Array;
		//private vars
		private var _highlight:Boolean=false;
		private var _enhance:Boolean=false;
		//private var _outline:Boolean=false;
		//private var _project:Boolean=false;
		// getters and setters
		public function get point():Point{return new Point(this.x, this.y);}
		public function get highlighted():Boolean{return _highlight}
		public function get enhanced():Boolean{return _enhance}
		//public function get outlining():Boolean{return _outline}
		//public function get projecting():Boolean{return _project}
		public function get pinned():Boolean{return _pinned;}
		public function get ppinned():Boolean{return _ppinned;}
		public function get fixed():Boolean{return _fixed;}
		public function set highlight(b:Boolean):void{_highlight=b;redraw();}
		public function set enhance(b:Boolean):void{_enhance=b;redraw();}
		//public function set outline(b:Boolean):void{_outline=b;redraw();}
		//public function set project(b:Boolean):void{_project=b;redraw();}
		public function set pin(b:Boolean):void {_pinned=b; redraw();}
		public function get segmentcount():int{return drawSegments.length;}
		
		
		public function moveTo(_x:Number, _y:Number):Boolean
		{
			if(this.parent != null)		
			{
				if (!pinned)
				{
					if (DrawingPanel(parent).isValidPoint(_x, _y))
					{
						this.x = _x; this.y = _y;
						for each (var s:DrawSegment in this.drawSegments)
						{
							s.redraw(this);
							
							for each (var a:DrawAngle in s.point1.drawAngles)
							{
								a.redraw(this);
							}
							for each (a in s.point2.drawAngles)
							{
								a.redraw(this);
							}
						}
						return true;
					}
				}
			}
			return false;
		}
		
		public function DrawPoint(id:String="", pinned:Boolean = false, fixed:Boolean = false, auto_ppinned:Boolean=true)
		{
			this.pointsize = ShapeProductionTask.unit*POINT_SIZE;
			this.enhancedsize = ShapeProductionTask.unit*ENHANCED_SIZE;
			this.pinnedsize = ShapeProductionTask.unit*PIN_SIZE;
			//if (fixed) pinnedsize *= 1.5;
			this.id = id;
			this._pinned = pinned;
			this._fixed = fixed;
			if (auto_ppinned && pinned && fixed) _ppinned = true;
			this.mouseEnabled = false;
			
			drawSegments = new Array();
			drawAngles = new Array();
			redraw();
			
		}
		public function addSegment(s:DrawSegment):Boolean
		{
			if (drawSegments.length == 0 || drawSegments.indexOf(s) == -1)
			{	
				drawSegments.push(s);
				return true;
			} else
			{
				return false;
			}
		}
		public function removeSegment(s:DrawSegment):Boolean
		{
			if (drawSegments.length >0 && drawSegments.indexOf(s) > -1)
			{
				drawSegments.splice(drawSegments.indexOf(s),1);
				return true;
			} else
			{
				return false;
			}
		}
		public function redrawSegments():void
		{
			for (var i:int=0; i < drawSegments.length; i++)
			{
				DrawSegment(drawSegments[i]).redraw();
			}
		}
		public function addAngle(a:DrawAngle):Boolean
		{
			if (drawAngles.length == 0 || drawAngles.indexOf(a) == -1)
			{	
				drawAngles.push(a);
				return true;
			} else
			{
				return false;
			}
		}
		public function removeAngle(a:DrawAngle):Boolean
		{
			if (drawAngles.length >0 && drawAngles.indexOf(a) > -1)
			{
				drawAngles.splice(drawAngles.indexOf(a),1);
				return true;
			} else
			{
				return false;
			}
		}
		public function redrawAngles():void
		{
			for (var i:int=0; i < drawAngles.length; i++)
			{
				DrawAngle(drawAngles[i]).redraw();
			}
		}
		// draw with current settings
		public function redraw():void
		{
			if (highlighted)
			{
				//trace("in point redraw");
				this.graphics.clear();
				if (fixed)
				{
					this.graphics.lineStyle(pointsize/5,FIXED_COLOR);
				} else
				{
					this.graphics.lineStyle(pointsize/5,POINT_COLOR);	
				}
				//this.graphics.lineStyle(pointsize/5,HIGHLIGHT_COLOR);
				this.graphics.beginFill(HIGHLIGHT_COLOR);
				if (enhanced)
				{
					this.graphics.drawEllipse(-enhancedsize/2, -enhancedsize/2, enhancedsize, enhancedsize);
				} else 
				{
					this.graphics.drawEllipse(-pointsize/2, -pointsize/2, pointsize, pointsize);
				}
				this.graphics.endFill();
				if (pinned)
				{
					this.graphics.lineStyle(pinnedsize/12,0xAAAA00);
					if (fixed)
					{
						this.graphics.beginFill(PIN_FIXED_COLOR);
					} else
					{
						this.graphics.beginFill(PIN_COLOR);	
					}
					this.graphics.drawEllipse(-pinnedsize/2, -pinnedsize/2, pinnedsize, pinnedsize);
					this.graphics.endFill();
				}				
			} else
			{
				this.graphics.clear();
				if (pinned && fixed)
				{
					this.graphics.lineStyle(pointsize/5,PINNED_FIXED_COLOR);
					this.graphics.beginFill(PINNED_FIXED_COLOR);
				} 
				else if (fixed)
				{
					this.graphics.lineStyle(pointsize/5,FIXED_COLOR);
					this.graphics.beginFill(FIXED_COLOR);
				} else
				{
					this.graphics.lineStyle(pointsize/5,POINT_COLOR);	
					this.graphics.beginFill(POINT_COLOR);
				}
				if (enhanced)
				{
					this.graphics.drawEllipse(-enhancedsize/2, -enhancedsize/2, enhancedsize, enhancedsize);
				} else 
				{
					this.graphics.drawEllipse(-pointsize/2, -pointsize/2, pointsize, pointsize);
				}
				this.graphics.endFill();
				if (pinned)
				{
					this.graphics.lineStyle(pinnedsize/6,0x000000);
					if (fixed)
					{
						this.graphics.beginFill(PIN_FIXED_COLOR);
					} else
					{
						this.graphics.beginFill(PIN_COLOR);	
					}
					this.graphics.drawEllipse(-pinnedsize/2, -pinnedsize/2, pinnedsize, pinnedsize);
					this.graphics.endFill();
				}
			}			
		} 
			
		
		//// Some functions for interaction
		/** This function finds the segment, from the array of segments, that is closest to perpendicular to the given segment 
		 * Used to select a segment for adjusting angle
		 */
		public function getRightestSegment(segment:DrawSegment):DrawSegment
		{
			var prevDeg:Number = 180;
			var tsegment:DrawSegment = null;
			for each (var s:DrawSegment in drawSegments)
			{
				if (s != segment)
				{
					var d:Number = MathUtilities.calcAcuteRotation(segment.rotation, s.rotation);
					if (d < prevDeg)
					{
						prevDeg = d;
						tsegment = s;
					}
				}
			}
			return tsegment;
		}
		
		public function getRightestAngle(segment:DrawSegment):DrawAngle
		{
			var prevDeg:Number = 180;
			var tangle:DrawAngle = null;
			for each (var a:DrawAngle in drawAngles)
			{
				// is this segment a part of the current angle?
				if (a.segment1 == segment || a.segment2 == segment)
				{
					var d:Number = MathUtilities.calcAcuteRotation(segment.rotation, a.otherDrawSegment(segment).rotation);
					if (d < prevDeg)
					{
						prevDeg = d;
						tangle = a;
					}
				}
			}
			return tangle;
		}
	}		
}